home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / cimcat.arc / CIMCAT.C next >
Text File  |  1990-03-21  |  14KB  |  469 lines

  1. /* Program CISCAT
  2.    This program reads each file in a directory that has an extension
  3.    of *.THD
  4.    These files are the downloaded threads from the new CompuServe
  5.    CIM (Compuserve Information Manager<tm>) program.  Each will have
  6.    one or more messages, all the same subject.
  7.  
  8.    Purpose of this program is to build a single ASCII output file
  9.    containing ASCII versions of these messages, as if a person had
  10.    read the messages in ASCII and captured the stream (IE, using the
  11.    "RTN" command to a capture file).
  12.  
  13.    Michael Gordon
  14.  
  15. */
  16.  
  17. #define STDOUT 1
  18.  
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <dir.h>
  23. #include <dos.h>
  24. #include <string.h>
  25. #include <io.h>
  26. #include <alloc.h>
  27. #include <ctype.h>
  28. #include <fcntl.h>
  29.  
  30. #define TRUE  1
  31. #define FALSE 0
  32. #define INBUFSIZE   (unsigned)30720  /* input buffer (60 sectors) */
  33. #define OUTBUFSIZE  (unsigned)6000  /* output buffer (for 10 sectors) */
  34.  
  35. typedef enum {NOFLUSH, FLUSHAFTER, FLUSH};
  36.  
  37. /* description of *.THD files as determined by inspection.
  38.    char version[7] = "VIS000\x1A";
  39.    int  unk1; = 75 = 0x4B
  40.    char unk2 = 3;
  41.    char hdate1[6];        6 bytes: sec min hr day month year-76
  42.    char hdate2[6];        ditto.  why 2?
  43.    long unk3 = 0x75;      ?
  44.    -- variable length fields --
  45.    [size byte=n][string of n-bytes]  topic/subject
  46.    [size byte=n][string of n-bytes]  section
  47.    [size byte=n][string of n-bytes]  forum
  48.    [size byte=n][string of n-bytes]  forum short name (DOS subdir name)
  49.    -- now a DOS information block --
  50.    int = n             skip forward n bytes to skip to message block
  51.   |    char = 1
  52.   |    [size byte=n][string of n-bytes]  directory name
  53.   |    long = file number.  Converted to hex digits, lz supp, = file name.
  54.   |    [size byte=n][string of n-bytes]  forum name (why again?)
  55.   `-> begin message block
  56. -------------------- repeated for each message -------------------------
  57.    int n = 0000        reverse link?  status?
  58.    int textmsg = nnnn  bytes to add to addr this word to find text-2
  59.    |   long msgnumber      this message's number
  60.    |   long parent         message number of parent msg
  61.    |   long reply          message number of first reply
  62.    |   long reply2         ?
  63.    |   char number_replies
  64.    |   char msg_date[6]    6 byte date-time
  65.    |   char msg_date[6]    ditto.  why 2?
  66.    |   [size byte=n][string of n-bytes]  From: name
  67.    |   [size byte=n][string of n-bytes]  From: ID
  68.    |   [size byte=n][string of n-bytes]  TO: name
  69.    |   [size byte=n][string of n-bytes]  TO: ID
  70.    |   char = x            status byte?
  71.    `int nextmsg (text-2)   bytes to add to this addr to get next msg block
  72.                            also, (nextmsg-2)= size of message body
  73.     char text[nextmsg-2]   body of message
  74. -------------------------------------------------------------------- */
  75.  
  76. /* the header is fixed.  After the header, things must be parsed. */
  77.  
  78. struct {
  79.    char version[7];     /* "VIS000\x1A"   */
  80.    int  unk1;
  81.    char unk2;
  82.    char hdate1[6];     /* 6 bytes: sec min hr day month year-76 */
  83.    char hdate2[6];     /* ditto.  why 2?   */
  84.    unsigned int sec_forum_ptr;  /* address of section, forum strings */
  85.    int  unk3;
  86.    } * theader;
  87.  
  88. char subject[40];
  89. char section[40];
  90. char forum[40];
  91. char toname[40];
  92. char touid[40];
  93. char fromname[40];
  94. char fromuid[40];
  95. char statusbyte;
  96. char numreplies;
  97. char mdate1[6];
  98. char mdate2[6];
  99. char datestring[40];
  100. char *months[14]={"???","Jan","Feb","Mar","Apr","May","Jun","Jul",
  101.                  "Aug","Sep","Oct","Nov","Dec","???"};
  102.  
  103. unsigned int reverselink;
  104. char * bodybegins;
  105. char * nextmsg;
  106. char * lid;              /* stop when just < this address */
  107. long msg_number;
  108. long parent;
  109. long reply;
  110. long reply2;
  111.  
  112. int inhandle;             /* which one are we using      */
  113. int totalmsgs;
  114. unsigned int bytesin;     /* bytes in inbuffer           */
  115. unsigned int bytesout;    /* bytes in out buffer         */
  116. unsigned buffersize;      /* for search buffer and index */
  117. char finder[] = "????????.THD";
  118. char crlf[] = {13,10,13,10,13,10,0};
  119. char * inbuffer;
  120. char * outbuffer;
  121. char * outpointer;
  122. union {
  123.   char * c;
  124.   unsigned int *w;
  125.   long * l;
  126.   } parser;
  127.  
  128.  
  129.  
  130. void write_bytes(char * instring, int numbytes)
  131. {
  132. int i;
  133.   for (i=0;i<numbytes;i++)
  134.   {  *outpointer = *instring;
  135.      bytesout++;
  136.      instring++;
  137.      outpointer++;
  138.      if (bytesout>=5120)
  139.      {  _write(STDOUT,outbuffer,bytesout);
  140.          bytesout=0;
  141.          outpointer=outbuffer;
  142.      }
  143.   }
  144. }
  145.  
  146.  
  147.  
  148. void parsemessages(void)
  149. {
  150. int i;
  151. char ch;
  152. char * endline;
  153. char temps[40];
  154. unsigned bytesintext;
  155. unsigned bytestowrite;
  156. int numintopic;
  157.  
  158.     /* header structure already pointing at the buffer beginning */
  159.     /* find and build the SUBJECT, SECTION, FORUM  line */
  160.     numintopic=0;
  161.     parser.c = inbuffer + sizeof(theader[0]);
  162.  
  163.     memset(subject,0,sizeof(subject));
  164.     memcpy(subject,parser.c+1,*parser.c);  /* copies subject */
  165.     parser.c += *parser.c;
  166.     parser.c ++;                         /* point to section */
  167.  
  168.     _write(2,subject,strlen(subject));   /* report progress */
  169.     _write(2," ________________________________________",
  170.           40-strlen(subject));  /* sort of a "tab" stop */
  171.  
  172.     memset(section,0,sizeof(section));
  173.     memcpy(section,parser.c+1,*parser.c);  /* copies subject */
  174.     parser.c += *parser.c;
  175.     parser.c ++;                         /* point to forum name */
  176.  
  177.     memset(forum,0,sizeof(forum));
  178.     memcpy(forum,parser.c+1,*parser.c);  /* copies subject */
  179.     parser.c += *parser.c;
  180.     parser.c ++;                         /* point to directory name */
  181.  
  182.     parser.c += *parser.c;                  /* skip for now */
  183.     parser.c ++;                         /* point to forum name */
  184.  
  185.     parser.c += *parser.w;  /* skip more text (DOS block) */
  186.  
  187.     do
  188.     {
  189.           /* now pointing into a message block */
  190.  
  191.           numintopic++;
  192.           totalmsgs++;
  193.  
  194.           reverselink =  *parser.w;
  195.           parser.c +=2;
  196.  
  197.           bodybegins = ( *parser.w) + parser.c; /* abs address */
  198.           parser.c +=2;
  199.  
  200.           msg_number =  *parser.l;
  201.           parser.c +=4;
  202.  
  203.           parent =  *parser.l;
  204.           parser.c +=4;
  205.  
  206.           reply  =  *parser.l;
  207.           parser.c +=4;
  208.  
  209.           reply2 =  *parser.l;
  210.           parser.c +=4;
  211.  
  212.           numreplies = *parser.c;
  213.           parser.c ++;
  214.  
  215.           memcpy(mdate1,parser.c,6);
  216.           parser.c +=6;
  217.  
  218.           memcpy(mdate2,parser.c,6);
  219.           parser.c +=6;
  220.  
  221.           memset(fromname,0,sizeof(fromname));
  222.           memcpy(fromname,parser.c+1,*parser.c);
  223.           parser.c += *parser.c;
  224.           parser.c++;
  225.  
  226.           memset(fromuid,0,sizeof(fromuid));
  227.           memcpy(fromuid,parser.c+1,*parser.c);
  228.           parser.c += *parser.c;
  229.           parser.c++;
  230.  
  231.           memset(toname,0,sizeof(toname));
  232.           memcpy(toname,parser.c+1,*parser.c);
  233.           parser.c += *parser.c;
  234.           parser.c++;
  235.  
  236.           memset(touid,0,sizeof(touid));
  237.           memcpy(touid,parser.c+1,*parser.c);
  238.           parser.c += *parser.c;
  239.           parser.c++;
  240.  
  241.           statusbyte = *parser.c;
  242.  
  243.           parser.c=bodybegins;  /* reset */
  244.           nextmsg = bodybegins +  *parser.w;
  245.           bytesintext = ( *parser.w) -2;
  246.           parser.c +=2;
  247.  
  248.           /* write the header stuff to stdout */
  249.           write_bytes("#: ",3);
  250.           ltoa(msg_number,temps,10);
  251.           write_bytes(temps,strlen(temps));
  252.           write_bytes(" S?/",4);
  253.           write_bytes(section,strlen(section));
  254.           write_bytes(crlf,2);
  255.  
  256.  
  257.           sprintf(datestring,"    %02d-%s-%04d  %02d:%02d:%02d",
  258.              mdate1[3],months[mdate1[4]],mdate1[5]+1980,
  259.              mdate1[2],mdate1[1],mdate1[0]);
  260.           write_bytes(datestring,strlen(datestring));
  261.           write_bytes(crlf,2);
  262.  
  263.           write_bytes("SB: ",4);
  264.           if (parent)
  265.           {  ltoa(parent,temps,10);
  266.              write_bytes("#",1);
  267.              write_bytes(temps,strlen(temps));
  268.              write_bytes("-",1);
  269.           }
  270.           write_bytes(subject,strlen(subject));
  271.           write_bytes(crlf,2);
  272.  
  273.           write_bytes("Fm: ",4);
  274.           write_bytes(fromname,strlen(fromname));
  275.           write_bytes(" ",1);
  276.           write_bytes(fromuid,strlen(fromuid));
  277.           write_bytes(crlf,2);
  278.  
  279.           write_bytes("To: ",4);
  280.           write_bytes(toname,strlen(toname));
  281.           write_bytes(" ",1);
  282.           write_bytes(touid,strlen(touid));
  283.           if (statusbyte & 0x08)
  284.             write_bytes(" (X)",4);
  285.           write_bytes(crlf,4);
  286.  
  287.  
  288.           /* now we are ready to parse the text. */
  289.           /* this is the slow way but gets the job done for now */
  290.  
  291.           do
  292.           {
  293.              if (bytesintext <79)
  294.              {
  295.                  bytestowrite = bytesintext;
  296.              }
  297.              else
  298.              {
  299.                 endline = parser.c + 78;
  300.  
  301.                 /* locate a suitable end of line */
  302.                 while ((*endline!=' ') && (endline > parser.c)) endline--;
  303.  
  304.                 if (endline==parser.c)   /* couldn't find a break */
  305.                   endline=parser.c + 77;    /* so reset to 78 */
  306.  
  307.                 bytestowrite = (endline - parser.c) + 1;
  308.              }
  309.  
  310.              /* write the line, checking for paragraph markers and
  311.                 lonely linefeeds.  On paragraph marker, just break out
  312.                 of the write loop and let it hit the crlf write.  This
  313.                 will automatically cause a new line of 78 to be parsed.
  314.                 If hit CR or LF, close out the line, too; and make sure
  315.                 that a CRLF combination doesn't cause the next line to
  316.                 start with the remnant LF. */
  317.              for (i=0;i<bytestowrite;i++)
  318.                 { ch=*parser.c;
  319.                   parser.c++;
  320.                   bytesintext--;
  321.                   if ((ch==0x40) && (*parser.c==0x62))
  322.                   {  /* paragraph marker */
  323.                      parser.c++;      /* skip the 'b' */
  324.                      break;          /* then break to the crlf write */
  325.                   }
  326.                   else
  327.                   {
  328.                      if (ch==13)
  329.                      {  if (*parser.c==10)    /* dump the crlf sequence */
  330.                         {  parser.c++;
  331.                            break;
  332.                         }
  333.                         break;               /* dump just the cr */
  334.                      }
  335.                      if (ch==10) break;      /* can't be a preceeding cr */
  336.                     write_bytes(&ch,1);
  337.                   }
  338.                 }  /* end of line write loop */
  339.  
  340.              write_bytes(crlf,2);
  341.  
  342.           } while ((parser.c < nextmsg) &&
  343.                    (parser.c < lid) &&
  344.                    (bytesintext>0));
  345.                       /* while lines exist in this msg */
  346.  
  347.           write_bytes(crlf,4);
  348.  
  349.           /* here show in output file how many replies # msg number of
  350.              the first reply. */
  351.           if (reply)
  352.           {  itoa(numreplies,temps,10);
  353.              write_bytes("          ",10);
  354.              write_bytes(temps,strlen(temps));
  355.              if (numreplies==1) write_bytes(" reply (",8);
  356.                 else       write_bytes(" replies (",10);
  357.              ltoa(reply,temps,10);
  358.              write_bytes(temps,strlen(temps));
  359.              if (reply==1) write_bytes(")",1);
  360.                 else write_bytes(",...)",5);
  361.           write_bytes(crlf,4);
  362.           }
  363.  
  364.           parser.c = nextmsg;     /* ensure alignment (failed before this) */
  365.     }  while ((parser.c < lid) && (nextmsg < (lid-sizeof(theader[0]))));
  366.                             /* while more messages are in thread */
  367.     itoa(numintopic,temps,10);
  368.     _write(2,temps,strlen(temps));   /* report progress */
  369.     _write(2,"      ",6-strlen(temps));
  370.     itoa(totalmsgs,temps,10);
  371.     _write(2,temps,strlen(temps));   /* report progress */
  372.     _write(2,crlf,2);
  373. }
  374.  
  375.  
  376.  
  377.  
  378.  
  379. void scan(void)
  380. {
  381. /*
  382. 4E   Find FIRST file.
  383.      On entry, DS:DX points to ASCIIZ with logged_drive, path, and filename.
  384.      CX=attribute for searching.
  385.  
  386. 4F   Find NEXT matching file.
  387.      Current DTA must contain info previously filled by Find FIRST (4E).
  388.      Error code 18 (decimal) returned if no more sources.
  389. */
  390. /* static struct REGPACK regs; */
  391. /*
  392.     unsigned    r_ax, r_bx, r_cx, r_dx;
  393.     unsigned    r_bp, r_si, r_di, r_ds, r_es, r_flags;
  394. */
  395. struct ffblk ffblk;
  396.  
  397. /*
  398.     char    logged_drive;             do not change
  399.     char    pattern[13];     these fields,
  400.     char    reserved[7];     Microsoft reserved
  401.     char    ff_attrib;
  402.     short    ff_ftime;
  403.     short    ff_fdate;
  404.     long    ff_fsize;
  405.     char    ff_name[13];     result of the search, asciiz
  406.  
  407. used with DOS functions 4E, 4F    */
  408.  
  409. int ret;
  410. char temps[33];
  411.   ret=findfirst(finder,&ffblk,0);
  412.   if (ret)
  413.   {  puts("No Files found");
  414.      exit(0);
  415.   }
  416.   do
  417.   { /* find next. report progress to STD ERR; incl file handle */
  418.      _write(2,ffblk.ff_name,strlen(ffblk.ff_name)); /* show progress */
  419.      _write(2,"  ",2);
  420.      inhandle=_open(ffblk.ff_name,0);
  421.      if (inhandle>0)
  422.      {  bytesin=_read(inhandle,inbuffer,buffersize);
  423.         if ((bytesin >0) && (memcmp(inbuffer,"VIS",3)==0))
  424.         {
  425.           lid = inbuffer + bytesin;
  426.           parsemessages();
  427.         }
  428.         _close(inhandle);
  429.      }
  430.      ret=findnext(&ffblk);
  431.   } while (!ret);
  432. }
  433.  
  434.  
  435.  
  436.  
  437. void main(void)
  438. {
  439.   inbuffer=farmalloc(INBUFSIZE);
  440.   buffersize=INBUFSIZE;
  441.   if (inbuffer==NULL)
  442.   { puts("Not enough memory for input buffer");
  443.     printf("Amount asked for %u bytes \n",INBUFSIZE);
  444.     printf("Amount in system %lu bytes \n",farcoreleft());
  445.     exit(1);
  446.   }
  447.   memset(inbuffer,0,buffersize);
  448.   theader=inbuffer;       /* point to the header structure */
  449.  
  450.   outbuffer=farmalloc(OUTBUFSIZE);
  451.   if (outbuffer==NULL)
  452.   { puts("Not enough memory for input buffer");
  453.     printf("Amount asked for %u bytes \n",OUTBUFSIZE);
  454.     printf("Amount in system %lu bytes \n",farcoreleft());
  455.     exit(1);
  456.   }
  457.   memset(outbuffer,0,OUTBUFSIZE);
  458.   bytesout=0;
  459.   outpointer=outbuffer;
  460.   _write(2,"CIMCAT version 1.1",18);
  461.   _write(2,crlf,4);
  462.   scan();
  463.   if (bytesout)
  464.   {  _write(STDOUT,outbuffer,bytesout);
  465.      bytesout=0;
  466.      outpointer=outbuffer;
  467.   }
  468. }
  469.